package com.sffzh.util.format;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sffzh.constant.Time;

public class JsonConvert {

	private String timeFormatPattern="yyyy-MM-dd HH:mm:ss";
	private GsonAnnotationExclusionStrategy exclusionVersion;
	private boolean expose;
	private boolean resultArray;//针对部分dojo页面的json数据，需要在json外面加上"[]"。当resultArray为true时，自动加上[]，结果表现为jsonArray.
	private String[] keys=new String[]{"items","numRows"};//外围关键字，如{rows:[],rowsNum:0}中，“rows”和“rowsNum”就是外围关键字注意：keys[0]对应List,key[1]对应记录总数

	/**
	 * //外围关键字，如{rows:[],rowsNum:0}中，“rows”和“rowsNum”就是外围关键字注意：keys[0]对应List,key[1]对应记录总数
	 * @param keys
	 * @return
	 */
	public JsonConvert setKeys(String[] keys){//外围关键字，如{rows:[],rowsNum:0}中，“rows”和“rowsNum”就是外围关键字注意：keys[0]对应List,key[1]对应记录总数
		if(keys!=null){
			this.keys=keys;
		}
		return this;
	}
	public JsonConvert setResultArray(boolean resultArray){
		this.resultArray=resultArray;
		return this;
	}
	public JsonConvert setExclusion(boolean expose){
		this.expose=expose;
		this.exclusionVersion=null;
		return this;
	}
	public JsonConvert setExclusionVersion(String version){
		if(version!=null&&!"".equals(version)){
			this.exclusionVersion=new GsonAnnotationExclusionStrategy(version);
		}
		return this;
	}
	
	/**
	 * 系统中使用的关键字组
	 * @author sffzh
	 *
	 */
	public enum KeysPair{
		ROWS_TOTALCOUNT,
		ITEMS_NUMROWS,
		
	}
	
	public JsonConvert setKeys(KeysPair keysPair){
		switch(keysPair){
		case ROWS_TOTALCOUNT:this.keys=new String[]{"rows","totalCount"};break;
		default:
		case ITEMS_NUMROWS:this.keys=new String[]{"items","numRows"};break;
		}
		return this;
	}

	/**
	 * 配置json转换时要用的时间日期格式，默认为yyyy-mm-dd HH:mm:ss
	 * @param parttern
	 * @return
	 */
	public JsonConvert setTimeFormatPattern(String pattern){
		this.timeFormatPattern=pattern;
		return this;
	}
	
	/**
	 * 配置json转换时要用的时间日期格式，默认为yyyy-mm-dd HH:mm:ss
	 * @param parttern，预置Full,Standard,Date,Time四种。其他格式用字符串手动表示。
	 * @return
	 */
	public JsonConvert setTimeFormatPattern(Time.Pattern pattern){
		this.timeFormatPattern=Time.getPatternStr(pattern);
		return this;
	}
	
	/**
	 * ☆
	 * 将对象转化为JSON
	 * @param obj
	 * @return
	 */
	public static String createJson(Object obj,boolean noDateContain){
		if(noDateContain){
			return JSONObject.fromObject(obj).toString();
		}
		Gson gson = new GsonBuilder().serializeNulls().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
		String json=gson.toJson(obj);
		return json.replace("\":null,\"", "\":\"\",\"").replace("\":null}","\":\"\"}");
	}
	
	/**
	 * ☆
	 * 将对象转化为JSON
	 * 默认包括日期转化
	 * @param obj
	 * @return
	 */
	public static String createJson(Object obj){
		return createJson(obj, false);
	}

	/**
	 * 返回格式如：{records:[{}]}
	 * @param list
	 * @return
	 */
	public static String ConvertListToPageJson(List<?> list) {
		JSONObject jn = new JSONObject();
		try {
			jn.put("records", list);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return jn.toString();
	}
	
	/**
	 * 不推荐使用。
	 * 建议使用 returnJSON(List<?>)(需要手动设置keys值)
	 * 用于管理端列表页获取的Json字符串的标准格式（[items—numRows]含时间转换），可以直接作为返回数据（普通端同样可直接用）
	 * @param x
	 * @return
	 */
	@Deprecated
	public String listTableJson(List<?> x){
		Map<String, Object> jsonMap = new HashMap<String, Object>();// 		
		jsonMap.put("items", x);//
		jsonMap.put("numRows", x.size());//total键 存放总记录数，必须的  			 
		Gson gson = new GsonBuilder().serializeNulls().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
		return gson.toJson(jsonMap);
	}

	@Deprecated
	public String addJsonItems(String result,String numRows){
		return  "{\"numRows\":"+numRows+",\"items\":"+result+"}";
	}
	
	//menu
	@Deprecated
	public String toMenuJson(String result){
		return "{'identifier': 'menuid','label': 'menuname','items':"+result+"}";
	}

	//转换时间  date to 标准时间
	@Deprecated
	public  XMLGregorianCalendar date2XMLGregorianCalendar(String str,String pattern) {
		 if(str == null||str.equals("")){
			 return null;
		 }else{
			Date date = DateUtil.parseDateString(str);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
	
			javax.xml.datatype.DatatypeFactory dtf = null;
			try {
				dtf = javax.xml.datatype.DatatypeFactory.newInstance();
			} catch (DatatypeConfigurationException e) {
				e.printStackTrace();
			}
			XMLGregorianCalendar dateArgs = dtf.newXMLGregorianCalendar(
					calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1,
					calendar.get(Calendar.DAY_OF_MONTH),
					calendar.get(Calendar.HOUR_OF_DAY  ), calendar.get(Calendar.MINUTE),
					calendar.get(Calendar.SECOND),
					calendar.get(Calendar.MILLISECOND),
					calendar.get(Calendar.ZONE_OFFSET) / (1000 * 60));
	
			return dateArgs;
		 }
	}
	//标准时间转string 
	@Deprecated
	public String xMLGregorianCalendar2Str(String temp) throws Exception {
		if(temp == null||temp.equals("")){
			 return "";
		 }else{
			 XMLGregorianCalendar xMLGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(temp);
			 SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			 Date date=new Date();
			 date=xMLGregorianCalendar.toGregorianCalendar().getTime();
			 String dateTimeString=simpleDateFormat.format(date);
			 return dateTimeString;
		 }
	 }
	
	/**
	 * 用于在需要向JSP返回数据处理状态（ok/error）和信息的Action中生成统一标准的用于返回的JSON字符串。格式为[{"status":"ok","msg":"helloworld"}]
	 * @param msg
	 * @param ok
	 * @param isArray 为true时返回json串为[{status:foo,msg:bar}]，为false时为{status:foo,msg:bar}
	 * @return
	 */
	public static String returnJson(String msg,boolean ok,boolean isArray){
		String status=ok?"ok":"error";
		if(isArray){
			return "[{\"status\":\""+status+"\",\"msg\":\""+msg+"\"}]";
		}
		else {
			return "{\"status\":\""+status+"\",\"msg\":\""+msg+"\"}";
		}
	}

	/**
	 * 用于在需要向JSP返回数据处理状态（ok/error）和信息的Action中生成统一标准的用于返回的JSON字符串。格式为[{"status":"ok","msg":"helloworld"}]
	 * @param msg
	 * @param ok  操作是否成功， 为true时 status:ok,为false时status:error
	 * @return "[{\"status\":\""+status+"\",\"msg\":\""+msg+"\"}]";
	 */
	public static String returnJsonArray(String msg,boolean ok){
		return returnJson(msg, ok, true);
	}
	
	/**
	 * 
	 * @param msg
	 * @param ok 操作是否成功， 为true时 status:ok,为false时status:error
	 * @return {status:"error",msg:“发生了错误”}
	 * 		   {status:"ok",msg:“操作成功”}
	 */
	public static String returnJson(String msg,boolean ok){
		return returnJson(msg, ok, false);
	}
	/**
	 * ☆
	 * @param msg
	 * @param ok
	 * @return {status:"error",msg:“发生了错误”}
	 * 		   {status:"ok",msg:“操作成功”}
	 */
	public static String returnJson(String msg,boolean ok,int code){
		String status=ok?"ok":"error";
		return "{\"status\":\""+status+"\",\"msg\":\""+msg+"\",\"code\":"+code+"}";
	}
	
	
	/**
	 * ☆
	 * @param msg
	 * @param ok
	 * @return {status:"error",msg:“发生了错误”,code:1}
	 * 		   {status:"ok",msg:“操作成功”,code:-1}
	 */
	public static String returnJsonWidthCode(String msg,boolean ok,int code){
		String status=ok?"ok":"error";
		return "{\"status\":\""+status+"\",\"msg\":\""+msg+"\",\"code\":"+code+"}";
	}

	/**
	 * 针对上面几个向手机端返回操作结果的结果字符串，反向解析，看该字符串表的是操作成功还是操作失败
	 * @param json
	 * @return
	 */
	public static boolean checkReturnJsonResultOk(String json){
		try {
			JSONObject jsonO=JSONObject.fromObject(json);
			String result=jsonO.getString("status");
			return "ok".equals(result);
		} catch (Exception e) {
			return false;
		}
	}
	
	/**
	 * 针对上面几个向手机端返回操作结果的结果字符串，反向解析，取得字符串中的code的值
	 * 如果json串中没有code，将返回0
	 * @param json
	 * @return
	 */
	public static int getReturnJsonResultCode(String json){
		try {
			JSONObject jsonO=JSONObject.fromObject(json);
			return jsonO.getInt("code");
		} catch (Exception e) {
			return 0;
		}
	}
	
	/**
	 * ☆
	 */
	public String returnJSON(List<?> list,int rowNum,String[] keys,String exclusionVersion){
		return returnJSON(list, rowNum,null, keys, exclusionVersion);
	}
	/**
	 * ☆
	 */
	public String returnJSON(List<?> list,int rowNum,String timePattern,String[] keys,String exclusionVersion){
		setKeys(keys);
		if("expose".equalsIgnoreCase(exclusionVersion)){
			setExclusion(true);
		}else
			setExclusionVersion(exclusionVersion);
		setTimeFormatPattern(timePattern);
		return returnJSON(list, rowNum);
	}
	
	/**
	 * ☆
	 * 
	 */
	public String returnJSON(List<?> list){
		return returnJSON(list,list==null?0:list.size());
	}
	
	/**
	 * ☆
	 * 标准方法
	 * @param list
	 * @param rowNum
	 * @return
	 */
	public String returnJSON(List<?> list,int rowNum){
		GsonBuilder builder=new GsonBuilder();
		builder.serializeNulls().setDateFormat(timeFormatPattern);
		if(expose){
			builder.excludeFieldsWithoutExposeAnnotation();
		}
		if(exclusionVersion!=null){
			builder.addSerializationExclusionStrategy(exclusionVersion);
		}
		//TODO 争议:目前设置为rowNum小于list大小时设置无效，采用list.size作为rowNum
		if(list!=null&&list.size()>rowNum){
			rowNum=list.size();
		}
		Gson gson = builder.create();
		Map<String,Object> map=new HashMap<String, Object>() ;
		map.put(keys[0], list);map.put(keys[1], rowNum);
		String json=gson.toJson(map);
		json=json.replace("\":null,\"", "\":\"\",\"").replace("\":null}","\":\"\"}");
		if(resultArray){
			return "["+json+"]";
		}
		return json;
	}
	
	
	//静态方法开始
	/**
	 * ☆
	 * 用于在需要向JSP返回数据列表的Action中生成统一标准的用于返回的JSON字符串。格式为{"items":"[{},{}]","numRows":"2"}
	 * 
	 * @param list
	 * @param keys 最终json的关键字名。如，dojo界面需要的data格式为{rows:[],totalCount:0}，则keys传["rows","totalCount"]数组
	 * @param exclusionVersion gosn过滤保留字段版本号.如果等于expose，则按expose注释过滤。
	 * @return
	 */
	public static String returnJson(List<?> list,int rowsNum ,String[] keys,String exclusionVersion){
		return new JsonConvert().returnJSON(list, rowsNum, null, keys, exclusionVersion);
	}
	public static String returnJson(List<?> list ,String[] keys,String exclusionVersion){
		return returnJson(list,list==null?0: list.size(),  keys, exclusionVersion);
	}
	
	public static String returnJson(List<?> list,String[] keys){
		return returnJson(list, keys,null);
	}

	public static String returnJson(List<?> list){
		return new JsonConvert().returnJSON(list, list.size());
	}
	/**
	 * ☆
	 * @param list
	 * @param  在有后端分页时，rowNum并不等于list的size
	 * @return
	 */
	public static String returnJson(List<?> list,int rowNum){
		return returnJson(list, rowNum, null, null);
	}
	
	/**
	 * ☆
	 * @param list
	 * @param exclusionVersion
	 * @return
	 */
	public static String returnJson(List<?> list,String exclusionVersion){
		return new JsonConvert().returnJSON(list, 0, null, exclusionVersion);
	}
	
	public static String  returnJson(List<?> list,int rowsCount,String[] keys){
		return returnJson(list, rowsCount,  keys, null);
	}
	
	/**
	 * 这个方法从JSONObject　或JSONArray中筛选出仅仅需要的属性，以简化JSON字符串的长度
	 * @param object
	 * @param titles
	 * @return
	 */
	@Deprecated
	public static String perfectJson(Object object,String[] titles){
		StringBuilder str=new StringBuilder();
		for(String t:titles){
			str.append(t).append(", ");
		}
		return perfectJson(object,str.toString());
	}
	
	/**
	 * 这个方法从JSON　或JSONArray中筛选出仅仅需要的属性，以简化JSON字符串的长度
	 * @param object　//传入一个JSONObject对象或JSONArray对象
	 * @param titles
	 * @return
	 */
	@Deprecated
	public static String perfectJson(JSON json,String titles){
		return perfectJson((Object) json,titles);
	}
	
	/**
	 * 从JSON　或JSONArray中筛选出仅仅需要的属性，以简化JSON字符串的长度
	 * 同时，如果源Json创建中使用了Gson的方法，将可能出现值为null的字段。这些字段在某些脚本中可能无法识别。
	 * 这个方法会将所有 null转为"null",空字符串转为""。
	 * @param json 源JSon的字符串形式
	 * @param titles
	 * @return
	 */
	@Deprecated
	public static String perfectJsonStr(String json,String titles){
		json=json.replace("\":null,\"", "\":\"\",\"").replace("\":null}","\":\"\"}");
		JSON j=JSONObject.fromObject(json);
		return perfectJson(j, titles);
	}
	
	/**
	 * 这个方法从JSON　或JSONArray中筛选出仅仅需要的属性，以简化JSON字符串的长度
	 * 筛选过程为使用JSONObject类遍历json的节点，逐一校验其子集
	 * 该方法已隐藏，通过调用上面的　perfectJson(JSON json,String titles)完成功能
	 * @param object　//传入一个JSONObject对象或JSONArray对象
	 * @param titles
	 * @return
	 */
	@Deprecated
	private static String perfectJson(Object object,String titles){
		if(!titles.contains(",")){
			titles=titles.replaceAll("[(\\s+)，。；、/\\;　]", ",");
		}
		titles=","+titles+",";
		if(object instanceof String||object instanceof Boolean||object instanceof Integer||object instanceof Double)return String.valueOf(object);
		if(object instanceof JSONArray){
			List<String> list=new ArrayList<String>();
			for(Object o:((JSONArray) object).toArray()){
				String item=perfectJson(o,titles);
				if(item!=null)list.add(item);
				
			}
			return JSONArray.fromObject(list).toString();
		}
		if(object instanceof JSONObject){
			JSONObject json;
			json=(JSONObject) object;
			Map<String,Object> map=new HashMap<String, Object>();
			@SuppressWarnings("unchecked")
			Set<String> entrySet= json.keySet();
			for(String t:entrySet){
				Object obj=json.get(t);
				if(titles.indexOf(","+t+",")>=0){
					if(obj==null){
						map.put(t, "");
					}
					else if(obj instanceof String||obj instanceof Boolean||obj instanceof Integer||obj instanceof Double){
						map.put(t, String.valueOf(obj));
					}
					else{//当obj为json或jsonArray时，若其键名被指定，则完整保留其内容
						map.put(t,obj);
					}
				}else if(obj instanceof JSONObject){
					String mapObject=perfectJson(obj, titles);
					if(mapObject!=null)map.put(t, JSONObject.fromObject(mapObject));
				}else if(obj instanceof JSONArray){
					String mapObject=perfectJson(obj, titles);
					if(mapObject!=null)map.put(t, JSONArray.fromObject(mapObject));
				}
			}
			if(map.isEmpty()){
				return null;
			}else
			return JSONObject.fromObject(map).toString();
		}
		System.out.println("错误！出现了无法处理的对象："+String.valueOf(object));
		return "#JSONERROR#"+String.valueOf(object)+"#JSONERROR#";
	}
	
	
	/**
	 * 规范化方法：
	 * 返回统一格式的接口
	 * 建议使用message内置方法：message.toJson()，或者message.toString()效果是一样的哦
	 * @return
	 */
	public static String jsonData(Message message){
		return message.toJson();
	}
	
	
	public static void main(String[] args) throws ParseException {//TODO 测试方法
		System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&");
		String a="[\"123\",{\"c\":'a',\"a\":[{\"aA\":\"aAVal\"},\"asdf\",{\"aB\":\"aBVal\",\"aB2\":\"aB2Val\",\"aB2\":{\"aBA\":\"aBAVal\"}}],\"b\":\"bVal\"}]";
		JSONArray json=JSONArray.fromObject(a);
		System.out.println(json.size());
		System.out.println(json.get(1).getClass().getName());
		System.out.println(a);
		System.out.println(perfectJson(json, "c,aB,aB2"));
//		JSONArray c=(JSONArray)b;
//		for(Object o:c.toArray()){
//			System.out.println(o+">>>"+o.getClass().getName());
//		}
	}
	//[{"items":[{"userid":0,"nickname":"","username":"user2","identityid":"","mobileNo":"","password":"","regtime":"","regtimeStr":"","mail":"","gender":"","birthDate":"1992-11-07 00:00:00","birthDateStr":"","isrelatepayaccount":"","signDate":"","effectDate":"","expireDate":"","parkId":0,"parkName":"","parkIdStr":"","roleId":0,"roleName":"","agreeVersion":"","payaccount":"","payAccountType":"","funcauth":"","filePath":"","fileName":"","fileType":"","payAccontStatus":"","parentUserId":0,"remark1":"","remark2":"","remark3":"","remark4":"","remark5":""},{"userid":0,"nickname":"","username":"user1","identityid":"","mobileNo":"","password":"","regtime":"","regtimeStr":"","mail":"","gender":"","birthDate":"2015-01-28 17:04:54","birthDateStr":"","isrelatepayaccount":"","signDate":"","effectDate":"","expireDate":"","parkId":0,"parkName":"","parkIdStr":"","roleId":0,"roleName":"","agreeVersion":"","payaccount":"","payAccountType":"","funcauth":"","filePath":"","fileName":"","fileType":"","payAccontStatus":"","parentUserId":0,"remark1":"","remark2":"","remark3":"","remark4":"","remark5":""}],"numRows":2}]

}
